#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAX_BUFF_SIZE 4096

#define ServerIP "113.98.195.202"
#define ServerPort 10038
#define Listenport 8880

#define cycle_time 1667
#define max_power 40.0
#define max_voltage 12.0

#define GPIO_LED_OUT2 "/sys/class/leds/ap147:green:lan2/brightness"
#define GPIO_LED_OUT "/sys/devices/gpio-leds.4/leds/awf-5g:wlan/brightness"

#define mac_uri "/sys/class/net/eth0/address"

int g_ServerSocket = 0;
int power_level = 100;

int SysClosing = 0;
int TimeAdjust = 0;

char ID_MAC[32] = {0};


static pthread_t recv_thread_t;
static pthread_t auto_work_thread_t;
static pthread_t pwm_thread_t;

unsigned int SequenceId = 1;


int GPIO_FD = 0;

// 根据IP和端口发送数据
void SendData(char *ip, unsigned short port, char *buff, unsigned int length)
{
	int len = sizeof(struct sockaddr_in);
	int sendlen = 0;
	struct sockaddr_in remoteaddr;

	remoteaddr.sin_family = AF_INET;
	remoteaddr.sin_addr.s_addr = inet_addr(ip);
	remoteaddr.sin_port = htons(port);

	sendlen = sendto(g_ServerSocket, buff, length, 0, (struct sockaddr *)&remoteaddr, len);

	printf("[UDP][Send][%s:%d][Length:%d]\n%s\n", inet_ntoa(remoteaddr.sin_addr), ntohs(remoteaddr.sin_port), length, buff);
	if(sendlen == -1)
		printf("Send UDP Socket Error.\n");
}

void SendStringData(char *ip, unsigned short port, char *buff)
{
	SendData(ip, port, buff, strlen(buff));
}

// 设置GPIO
void SetGPIO(const char *devuri, char *value)
{
	int fd = 0;

	if ((fd = open(devuri, O_RDWR)) < 0)
	{
		printf("Can not open dev %s .\n", devuri);
		return;
	}

	write(fd, value, strlen(value));
	close(fd);
}

void InitGPIO(const char *devuri)
{
	if ((GPIO_FD = open(devuri, O_WRONLY)) < 0)
	{
		printf("Can not open dev %s .\n", devuri);
		return;
	}
}

void SetGpio(char *value)
{
	if(!GPIO_FD)
		return;

	//lseek(GPIO_FD, 0, SEEK_SET);
	write(GPIO_FD, value, strlen(value));
}

void ReleaseGPIO()
{
	close(GPIO_FD);
}


// 执行指令并且获取回应
unsigned int ExcuteCmd(const char *cmd, char *resultstr, unsigned int resultsize)
{
	FILE *fd;

	memset(resultstr, 0, resultsize);
	if( (fd = popen(cmd, "r")) == NULL )
		return 0;

	while(fgets(resultstr + strlen(resultstr), 2048, fd))
	{
		//
	}

	pclose(fd);
	return strlen(resultstr);
}

void excuteCmd(const char *cmd)
{
	system(cmd);
}


// 提取字符串中的数字
int ParseIntInStr(char *ostr)
{
	char intstr[32] = {0};
	char *rdind = ostr, *wtind = intstr;

	int found = 0;
	while(*rdind)
	{
		if((*rdind) >= '0' && (*rdind) <= '9')
		{
			*(wtind ++) = (*rdind);
			found = 1;
		}
		else
		{
			if(found)
				break;
		}
		rdind ++;
	}
	return atoi(intstr);
}


void WriteWrtPwm()
{
	int pwmout = 65535 * power_level / 100;
	char pwmstr[64] = {0};
	sprintf(pwmstr, "spi-bridge write \"pwmWrite 0 %d\"", pwmout);
	excuteCmd(pwmstr);
	printf("Set spi pwm 0 %d\n", pwmout);
}


// 设置时间
int SetSystemTime(char *dt)
{  
	struct tm rtm;
	struct tm _tm;
	struct timeval tv;
	time_t timep;
	sscanf(dt, "%d-%d-%d %d:%d:%d", &rtm.tm_year,
		&rtm.tm_mon, &rtm.tm_mday,&rtm.tm_hour,
		&rtm.tm_min, &rtm.tm_sec);
	_tm.tm_sec = rtm.tm_sec;
	_tm.tm_min = rtm.tm_min;
	_tm.tm_hour = rtm.tm_hour;
	_tm.tm_mday = rtm.tm_mday;
	_tm.tm_mon = rtm.tm_mon - 1;
	_tm.tm_year = rtm.tm_year - 1900;

	timep = mktime(&_tm);
	tv.tv_sec = timep;
	tv.tv_usec = 0;
	if(settimeofday (&tv, (struct timezone *) 0) < 0)
	{
		printf("Set system datatime error!/n");
		return -1;
	}
	return 0;
}


// 读取MAC地址
unsigned int ReadKeyMac(char *mac)
{
	int fd = 0;
	unsigned int length = 0;
	char *st = 0;

	if ((fd = open(mac_uri, O_RDONLY)) < 0)
	{
		printf("Can not open mac file %s .\n", mac_uri);
		return;
	}

	length = read(fd, mac, 32);
	close(fd);

	if(st = strchr(mac, ' ')) (* st) = 0;
	if(st = strchr(mac, '\n')) (* st) = 0;
	if(st = strchr(mac, '\t')) (* st) = 0;

	return strlen(mac);
}

// 绑定端口
void BindSock(unsigned short listenport)
{
	struct sockaddr_in serveraddr;

	// 绑定IP、端口
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = INADDR_ANY;
	serveraddr.sin_port = htons(listenport);

	// 绑定指定的端口
	bind(g_ServerSocket,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
}

// 接收到数据的处理函数
void OnRecvData(char *ip, unsigned short port, char *buff, unsigned int length)
{
	if(strstr(buff, "\"cmd\":\"Settings\""))
	{
		char *tag1 = "\"lpower\":\"";
		char *st = 0, *ed = 0;
		char val[32] = {0};
		int i_val = 0;
		if(st = strstr(buff, tag1))
		{
			st += strlen(tag1);
			ed = strstr(st, "\"");
			memcpy(val, st, ed - st);
			i_val = atoi(val);
			if(i_val < 0) i_val = 0;
			if(i_val > 100) i_val = 100;
			power_level = i_val;
			printf("Set output power %d %%\n\n", power_level);
			WriteWrtPwm();
		}
	}
}

// 接收循环线程函数
void RecvThreadFunc(const void *arg)
{
	struct sockaddr_in RemoteAddr;
	unsigned int len = sizeof(struct sockaddr_in);
	int recvlen = 0;
	char cmdstr[MAX_BUFF_SIZE];
	unsigned int cmdlen;

	while(1)
	{
		memset(cmdstr, 0, MAX_BUFF_SIZE);
		// 接受不能出错，收到的数据也不能太小
		while((recvlen = recvfrom(g_ServerSocket, cmdstr, MAX_BUFF_SIZE, 0, (struct sockaddr *)&RemoteAddr, &len)) < 0)
		{
			if(SysClosing)
				return;
			memset(cmdstr, 0, MAX_BUFF_SIZE);
		}

		printf("[UDP][Recv][%s:%d][Length:%d]\n%s\n", inet_ntoa(RemoteAddr.sin_addr), ntohs(RemoteAddr.sin_port), recvlen, cmdstr);

		// 此处处理接收到的数据
		OnRecvData(inet_ntoa(RemoteAddr.sin_addr), ntohs(RemoteAddr.sin_port), cmdstr, recvlen);
	}
}

// 自动上报循环线程
void AutoSendWorkFunc(const void *arg)
{
	char cmdstr[MAX_BUFF_SIZE];
	char cmdoutbuff[4096] = {0};
	int readadc = 0;
	unsigned int cmdlen, cmdoutlen;
	double now_current;

	sprintf(cmdstr, "{\"sid\":\"%d\",\"id\":\"21:3E:4F:36:55:72\",\"devtype\":\"3\",\"cmd\":\"Login\",\"data\":{\"factory\":\"TOZED\",\"model\":\"TZ-GS2169D-E3\",\"sn\":\"21000963710001\"}}",
		SequenceId ++);
	cmdlen = strlen(cmdstr);
	SendData(ServerIP, ServerPort, cmdstr, cmdlen);

	while(1)
	{
		memset(cmdstr, 0, MAX_BUFF_SIZE);

		now_current = (max_power * power_level) / (max_voltage * 100);
		excuteCmd("spi-bridge write \"analogRead 1\"");
		cmdoutlen = ExcuteCmd("spi-bridge read", cmdoutbuff, 4096);
		readadc = ParseIntInStr(cmdoutbuff);
		printf("Read adc: %d\n", readadc);
		now_current = (0.816 * readadc - 2500) / 185;

		sprintf(cmdstr, "{\"sid\":\"%d\",\"id\":\"21:3E:4F:36:55:72\",\"devtype\":\"3\",\"cmd\":\"LStatus\",\"data\":{\"voltage\":\"%.1lf\",\"current\":\"%.1lf\",\"wcount\":\"0\"}}",
			SequenceId ++, max_voltage, now_current);
		cmdlen = strlen(cmdstr);

		SendData(ServerIP, ServerPort, cmdstr, cmdlen);

		if(SysClosing)
			return;
		sleep(10);
		if(SysClosing)
			return;
	}
}

// 使用GPIO输出PWM信号
void PwmOutFunc(const void *arg)
{
	while(1)
	{
		sleep(1);
	}
}

int main(int argc,char **argv)
{
	printf("\nService Start! %s\n", argv[1]);

	excuteCmd("spi-bridge write \"pinMode 0 PWM\"");
	excuteCmd("spi-bridge write \"pinMode 1 INPUT_ANALOG\"");

	if(!argv[1])
	{
		printf("\nWait 90 secs.\n");
		sleep(90);
	}

	ReadKeyMac(ID_MAC);
	printf("\nDevice's key mac is %s  .\n", ID_MAC);

	g_ServerSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if( g_ServerSocket <= 0 )
	{
		printf("Create UDP Socket Error.\n");
		return -1;
	}
	else
		printf("Create UDP Socket Success (%d).\n", g_ServerSocket);

	// 绑定指定的端口
	BindSock(Listenport);

	// 初始化GPIO
	//InitGPIO(GPIO_LED_OUT);

	//SendData(ServerIP, ServerPort, "OKOKOK!", 7);
	pthread_create(&recv_thread_t, NULL, (void *)RecvThreadFunc, NULL);
	pthread_detach(recv_thread_t);

	pthread_create(&auto_work_thread_t, NULL, (void *)AutoSendWorkFunc, NULL);
	pthread_detach(auto_work_thread_t);

	//pthread_create(&pwm_thread_t, NULL, (void *)PwmOutFunc, NULL);
	//pthread_detach(pwm_thread_t);

	char cc;

	while(1)
	{
		if(!argv[1])
			sleep(2);
		else
		{
			cc = getchar();
			if(cc == 'q')
				break;
			else if(cc == 'u')
				power_level = 100;
			else if(cc == 'd')
				power_level = 0;
			else if(cc >= '1' && cc <= '9')
				power_level = 10 * (cc - '0');

			WriteWrtPwm();
		}
	}

	close(g_ServerSocket);
	SysClosing = 1;
	//ReleaseGPIO();

	printf("\nService Stoped!\n");

	return 0;
}

